package com.ls.fw.data.search.impl.dao;

import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.NumericRangeQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Sort;

import com.ls.fw.data.bean.PageBean;
import com.ls.fw.data.exception.DataException;
import com.ls.fw.data.search.impl.lucene.bean.ValueType;
import com.ls.fw.data.search.impl.lucene.handler.BeanHandler;
import com.ls.fw.data.search.impl.lucene.util.IndexUtil;
import com.ls.fw.data.utils.DataUtil;

@SuppressWarnings("unchecked")
public abstract class EntitySearchDaoAdapter<M, PK extends Serializable> extends SearchDaoImpl implements EntitySearchDao<M, PK>{
//
	/**
	 * 实体类类型(由机关办法主动赋值)
	 */
	protected Class<M> entityClass = null;
	
	protected Class<PK> pkClass = null;
	
	protected BeanHandler beanHandler  = new BeanHandler();
	
	
	public EntitySearchDaoAdapter() {
		super();
		init();
	}
 
	
	private void init(){
		if(entityClass == null){
			this.entityClass = DataUtil.getGenerricType(this.getClass());
		}
	}
	
	
	public EntitySearchDaoAdapter(String address, boolean commit) {
		super(address, commit);
		init();
	}

	public EntitySearchDaoAdapter(String address) {
		super(address);
		init();
	}


	@Override
	public boolean open(Object _address) {
		boolean flag = super.open(_address);
		init();
		return flag;
	}


	public Class<M> getEntityClass() {
		return this.entityClass;
	}


	public void setEntityClass(Class<M> entityClass) {
		this.entityClass = entityClass;
		init();
	}
  
	/**
	 * 设置实体信息
	 * 
	 * @author lisheng
	 * @date 2014年12月31日 下午7:01:46
	 * @version V1.0
	 * @param entityClass
	 * @param pkClass
	 */
	public EntitySearchDaoAdapter<M, PK> setEntityInfo(Class<M> entityClass,Class<PK> pkClass){
		this.entityClass = entityClass;
		this.pkClass = pkClass;
		init();
		return this;
	}
	
	@Override
	public M doc2Obj(final Document doc,final Query query,final boolean high){
		return this.doc2Obj(doc, entityClass, query, high);
	}
	

	@Override
	public M doc2Obj(final Document doc){
		return this.doc2Obj(doc, entityClass, null,false);
	}
	

	@Override
	public void save(final M model) throws DataException{
		IndexWriter writer = this.server.getIndexWriter();
		try {
			Document doc = this.getDocument(model);
			writer.addDocument(doc);
			if(this.isAutoCommit()){
				writer.commit();
			}
		} catch (Exception e) {
			if(this.isAutoCommit()){
				try {
					writer.rollback();
				} catch (IOException e1) {
					throw new DataException(e1.getMessage(),e1.getCause());
				}
			}
			throw new DataException(e.getMessage(),e);
		} finally {
		}
	}
	
	
	@Override
	public void save(final List<M> list) throws DataException{
		
		IndexWriter writer = this.getServer().getIndexWriter();
		try {
			List<Document> modellist = new ArrayList<Document>(list.size());
			for (M model : list) {
				Document doc = getDocument(model);
				modellist.add(doc);
			}
			writer.addDocuments(modellist);
			if(this.isAutoCommit()){
				writer.commit();
			}
		} catch (Exception e) {
			if(this.isAutoCommit()){
				try {
					writer.rollback();
				} catch (IOException e1) {
					throw new DataException(e1.getMessage(),e1.getCause());
				}
			}
			throw new DataException(e.getMessage(),e.getCause());
		} finally {
		}
	}
	
	
	@Override
	public void update(final M model,final PK id) throws DataException{
		IndexWriter writer = this.getServer().getIndexWriter();
		try {
			Term term = new Term(DEFAULT_PK, String.valueOf(id));
			Document doc = this.getDocument(model);
			writer.updateDocument(term, doc);
			if(this.isAutoCommit()){
				writer.commit();
			}
		} catch (Exception e) {
			if(this.isAutoCommit()){
				try {
					writer.rollback();
				} catch (IOException e1) {
					throw new DataException(e1.getMessage(),e1.getCause());
				}
			}
			throw new DataException(e.getMessage(),e.getCause());
		} finally {
		}
	}
	
	
	@Override
	public void delete(final PK id) throws DataException{
		this.delete(DEFAULT_PK, id);
	}
	
	
	@Override
	public void deleteAll() throws DataException{
		IndexWriter writer = this.getServer().getIndexWriter();
		try {
			// 删除时多条记录删除
			writer.deleteAll();
			if(this.isAutoCommit()){
				writer.commit();
			}
		} catch (Exception e) {
			if(this.isAutoCommit()){
				try {
					writer.rollback();
				} catch (IOException e1) {
					throw new DataException(e1.getMessage(),e1.getCause());
				}
			}
			throw new DataException(e.getMessage(),e.getCause());
		} finally {
		}
	}
	
	
	@Override
	public void delete(final String pkname,final PK id) throws DataException{
		IndexWriter writer = this.getServer().getIndexWriter();
		try {
			//NumericRangeQuery
			ValueType t = IndexUtil.getValueType(id);
			Query query = null;
			switch(t){
				case NONE:
					throw new DataException("id不能为空！");
				case DOUBLE:
					query = NumericRangeQuery.newDoubleRange(pkname, Double.valueOf(String.valueOf(id)), Double.valueOf(String.valueOf(id)), true, true);
					writer.deleteDocuments(query);
					break;
				case FLOAT:
					query = NumericRangeQuery.newFloatRange(pkname, Float.valueOf(String.valueOf(id)), Float.valueOf(String.valueOf(id)), true, true);
					writer.deleteDocuments(query);
					break;
				case LONG:
					query = NumericRangeQuery.newLongRange(pkname, Long.valueOf(String.valueOf(id)), Long.valueOf(String.valueOf(id)), true, true);
					writer.deleteDocuments(query);
					break;
				case INT:
					query = NumericRangeQuery.newIntRange(pkname, Integer.valueOf(String.valueOf(id)), Integer.valueOf(String.valueOf(id)), true, true);
					writer.deleteDocuments(query);
					break;
				case STRING:
					Term term = null;
				    term = new Term(pkname, String.valueOf(id));
				    writer.deleteDocuments(term);
					break;
			}
			if(this.isAutoCommit()){
				writer.commit();
			}
		} catch (Exception e) {
			if(this.isAutoCommit()){
				try {
					writer.rollback();
				} catch (IOException e1) {
					throw new DataException(e1.getMessage(),e1.getCause());
				}
			}
			throw new DataException(e.getMessage(),e.getCause());
		} finally {
		}
	}
	
	public PageBean query(Query query, Sort sort, int page, int pageSize,boolean high){
		return this.query(query, sort, page, pageSize, entityClass, high);
	}

}